/*
 Copyright (c) 2007-2008 The Regents of the University of California.
 All rights reserved.

 Permission is hereby granted, without written agreement and without
 license or royalty fees, to use, copy, modify, and distribute this
 software and its documentation for any purpose, provided that the
 above copyright notice and the following two paragraphs appear in all
 copies of this software and that appropriate acknowledgments are made
 to the research of the COSI group.

 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.

 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
 ENHANCEMENTS, OR MODIFICATIONS.

 Author : Alessandro Pinto <apinto@eecs.berkeley.edu>
 University of California, Berkeley
 545 Cory Hall, Berkeley, CA 94720
 */
#include "SyscCodeGen.h"

namespace cosi {

namespace io {

namespace onchipcommunication {

using namespace cosi::commstruct::onchipcommunication;
using namespace cosi::quantity::onchipcommunication;

void SyscCodeGen::SyscMakeFileGen() {

	string ExecName;

	int CurrentChar;
	CurrentChar = mFileName.size();
	while (mFileName[CurrentChar] != '.' && mFileName[CurrentChar] != '/') {
		CurrentChar --;
	}

	if (mFileName[CurrentChar] == '/') {
		ExecName = mFileName + ".x";
	} else {
		ExecName = string(mFileName, 0, CurrentChar) + ".x";
	}

	ofstream f;
	f.open(mMakefileName.c_str() );
	f << "COSIROOT=" << Configuration->GetCosiRoot() << endl;
	f << "SYSTEMC =" << Configuration->GetSystemCRoot() << endl;
	f << "CC= g++" << endl;
	f << "OPT= -O2" << endl;
	f << "DEBUG  = -g" << endl;
	f << "CFLAGS = $(OPT) $(DEBUG) $(OTHER)" << endl;
	f
			<< "INCLUDE = -I$(SYSTEMC)/include -I$(COSIROOT)/libraries/onchipcommunication/systemc"
			<< endl;
	f << "LIB = -L$(SYSTEMC)/lib-linux" << endl;
	f << "all: " << ExecName << endl;
	f << ExecName << ": " << mFileName << endl;
	f << "\t" << "$(CC) -o " << ExecName << " " << mFileName
			<< " $(COSIROOT)/libraries/onchipcommunication/systemc/Technology.cpp $(INCLUDE) $(LIB) -lsystemc"
			<< endl;
	f.close();
}

SyscCodeGen::SyscCodeGen(string FileName, string MakeFileName,
		Implementation* I, Specification* PtP, int pFlitWidth,
		double pClockPeriod) {

	mFileName = FileName;
	mMakefileName = MakeFileName;
	mFlitWidth = pFlitWidth;
	mClockPeriod = pClockPeriod;
	mI = I;
	mSpec = PtP;

}

void SyscCodeGen::Run() {
	SyscOpen();
	SyscScMain();
	//SyscPrintStat( f , G , PtP ) ;
	SyscClose();
	SyscMakeFileGen() ;

}

void SyscCodeGen::SyscOpen() {
	mF = new ofstream( mFileName.c_str( ) );
	(*mF) << "//Automatically generated by COSI NOC 1.3 " << endl;
	(*mF) << "#include <iostream>" << endl;
	(*mF) << "#include <map>" << endl;
	(*mF) << "#include <sstream>" << endl;
	(*mF) << "#include \"systemc.h\"" << endl;
	(*mF) << "#include \"SourceIp.h\"" << endl;
	(*mF) << "#include \"DestIp.h\"" << endl;
	(*mF) << "#include \"Router.h\"" << endl;
	(*mF) << "#include \"PtP.h\"" << endl;
	(*mF) << "#include \"Monitor.h\"" << endl;
	(*mF) << "#include \"Technology.h\"" << endl;
	(*mF) << endl;
}

void SyscCodeGen::SyscScMain() {

	(*mF) << "using namespace std ;" << endl;
	(*mF) << "#define FLITWIDTH " << mFlitWidth << endl;
	(*mF) << "#define CLOCKPERIOD " << mClockPeriod << endl;
	(*mF) << "#include \"CosiSysCutil.h\"" << endl;
	(*mF) << "int sc_main( int argc , char* argv[] ) {" << endl;
	(*mF) << "\t" << "TechnologyNode TechParam ;" << endl;

	(*mF) << "\t" << "TechParam = GetTechParameters( \""
			<< Configuration->GetCosiRoot()
			<< "/libraries/onchipcommunication/systemc/energy_10x10_100.dat\" ) ;"
			<< endl;

	(*mF) << "\t" << "Flow F ;" << endl;
	IdGraph::v_iterator U, V;

	//---------------------------------------------------------------------------
	//                    Instantiate all sources and destinations
	//---------------------------------------------------------------------------

	//For each Ip core such that the output port is bounded to some router
	//instantiate a source ip

	//TODO: single input-output port per IP core
	//currently we assume that each core has one input and output port
	//this assumption can be easily removed by using one source ip for each port.
	//We should provide a model for an IP that has multiple output ports and multiple
	//threads.

	for (U = mSpec->v_begin(); U != mSpec->v_end(); U++) {
		Ports::iterator Pit;
		int InId = 0;
		int OutId = 0;
		for (Pit = (*mI)[*U].PRJ(Ports)Begin(); Pit != (*mI)[*U].PRJ(Ports)End(); Pit ++) {
			Interface If = (*mI)[*U].PRJ(Ports)If(Pit) ;
			string Name = (*mI)[*U].PRJ(Ports)Name(Pit) ;
			bool IsBound = (*mI)[*U].PRJ(Ports)IsBound(Name) ;
			if (If.GetDirection() == Interface::OUT && IsBound) {
				OutputIndex(*U, Name, OutId);
				OutId++;
				(*mF) << SyscSource(*U, Name);
				(*mF) << SyscSourceNetworkInterface(*U, Name);
			}
			if (If.GetDirection() == Interface::IN && IsBound) {
				InputIndex(*U, Name, InId);
				InId++;
				(*mF) << SyscDest(*U, Name);
				(*mF) << SyscDestNetworkInterface(*U, Name);
			}
		}
	}

	//---------------------------------------------------------------------------
	//                    Instantiate all routers
	//---------------------------------------------------------------------------

	for (U = mI->v_begin(); U != mI->v_end(); U++) {
		if (!mSpec->InV(*U) ) {
			//map the ports
			Ports::iterator Pit;
			int InId = 0;
			int OutId = 0;
			for (Pit = (*mI)[*U].PRJ(Ports)Begin(); Pit != (*mI)[*U].PRJ(Ports)End(); Pit ++) {
				Interface If = (*mI)[*U].PRJ(Ports)If(Pit) ;
				string Name = (*mI)[*U].PRJ(Ports)Name(Pit) ;
				bool IsBound = (*mI)[*U].PRJ(Ports)IsBound(Name) ;
				if (If.GetDirection() == Interface::OUT) {
					OutputIndex(*U, Name, OutId);
					OutId++;
				}
				if (If.GetDirection() == Interface::IN) {
					InputIndex(*U, Name, InId);
					InId++;
				}
			}
			(*mF) << SyscRouter(*U);
		}
	}

	//---------------------------------------------------------------------------
	//                    Connect components
	//---------------------------------------------------------------------------

	for (U = mSpec->v_begin(); U != mSpec->v_end(); U++) {
		Ports::iterator Pit;
		for (Pit = (*mI)[*U].PRJ(Ports)Begin(); Pit != (*mI)[*U].PRJ(Ports)End(); Pit ++) {
			Interface If = (*mI)[*U].PRJ(Ports)If(Pit) ;
			string Name = (*mI)[*U].PRJ(Ports)Name(Pit) ;
			bool IsBound = (*mI)[*U].PRJ(Ports)IsBound(Name) ;
			if (If.GetDirection() == Interface::OUT && IsBound) {
				//there must be a source
				//connect the source to the interface
				(*mF) << "\t" << "COSI_SOURCE_TO_IF_CONNECTION( " << *U
						<< " , " << *U << " , 0 , 6 , 0.0 )  ; " << endl;
			}
			if (If.GetDirection() == Interface::IN && IsBound) {
				//conect the interface to the destination
				(*mF) << "\t" << "COSI_IF_TO_DEST_CONNECTION( " << *U
						<< " , 0 , " << *U << " , 6 , 0.0 ) ; " << endl;
			}
		}
	}

	//Connect source interfaces to routers
	for (U = mI->v_begin(); U != mI->v_end(); U++) {
		for (V = mI->v_begin(); V != mI->v_end(); V++) {
			if (mI->InE(*U, *V) ) {
				string P = (*mI)[*U].PRJ(Ports)IsBoundTo(Edge(*U, *V), Interface::OUT) ;
				int Upid = OutputIndex(*U, P) ;
				P = (*mI)[*V].PRJ(Ports)IsBoundTo(Edge(*U, *V), Interface::IN) ;
				int Vpid = InputIndex(*V, P) ;
				double Dist = Norm1((*mI)[*U].PRJ(Position)Get() , (*mI)[*V].PRJ(Position)Get() ) ;

				if ( !mSpec->InV(*U) && !mSpec->InV(*V)) {
					(*mF) << "\t" << "COSI_ROUTER_TO_ROUTER_CONNECTION( " << *U
							<< " , " << Upid << " , " << *V << " , " << Vpid
							<< " , 6 , " << Dist << " )  ; " << endl;
				} else if ( !mSpec->InV(*U) && mSpec->InV(*V)) {
					(*mF) << "\t" << "COSI_ROUTER_TO_IF_CONNECTION( " << *U
							<< " , " << Upid << " , " << *V << " , " << Vpid
							<< " , 6 , " << Dist << " )  ; " << endl;
				} else if (mSpec->InV(*U) && !mSpec->InV(*V)) {
					(*mF) << "\t" << "COSI_IF_TO_ROUTER_CONNECTION( " << *U
							<< " , " << Upid << " , " << *V << " , " << Vpid
							<< " , 6 , " << Dist << " )  ; " << endl;
				} else {
					(*mF) << "\t" << "COSI_IF_TO_IF_CONNECTION( " << *U
							<< " , " << Upid << " , " << *V << " , " << Vpid
							<< " , 6 , " << Dist << " )  ; " << endl;
				}
			}
		}
	}

	(*mF)
			<< "Monitor< FLITWIDTH> M(\"Monitor\" , 0.000001 , _CosiDestIpVector_ ) ;"
			<< endl;

	(*mF) << SyscTrace() ;

	(*mF) << "sc_start( 0.00001 , SC_SEC);" << endl;

	(*mF) << "M.WriteReport( ) ; " << endl;

	(*mF) << "sc_close_vcd_trace_file(trcf);" << endl ;

	(*mF) << "system(\"" << Configuration->GetTracerRoot() << "/" << Configuration->GetTracerExec() << " cosisyscsim.vcd\");" << endl ;

	(*mF) << "exit( 0 ) ; " << endl;

}

string SyscCodeGen::SyscTrace() {
	//trace souces and destinations
	stringstream s;
	s << "sc_trace_file *trcf= sc_create_vcd_trace_file(\"cosisyscsim\");"
			<< endl;
	IdGraph::v_iterator U ;
	for (U = mSpec->v_begin(); U != mSpec->v_end(); U++) {
		Ports::iterator Pit;
		int InId = 0;
		int OutId = 0;
		for (Pit = (*mI)[*U].PRJ(Ports)Begin(); Pit != (*mI)[*U].PRJ(Ports)End(); Pit ++) {
			Interface If = (*mI)[*U].PRJ(Ports)If(Pit) ;
			string Name = (*mI)[*U].PRJ(Ports)Name(Pit) ;
			bool IsBound = (*mI)[*U].PRJ(Ports)IsBound(Name) ;
			if (If.GetDirection() == Interface::OUT && IsBound) {
				s << "sc_trace(trcf, S" << *U << "_Data, \"" << mSpec->GetName(*U) << "_data_out\");" << endl ;
				s << "sc_trace(trcf, S" << *U << "_Valid, \"" << mSpec->GetName(*U) << "_valid_out\");" << endl ;
				s << "sc_trace(trcf, S" << *U << "_Ack, \"" << mSpec->GetName(*U) << "_ack_in\");" << endl ;
				s << "sc_trace(trcf, S" << *U << "_Full, \"" << mSpec->GetName(*U) << "_full_in\");" << endl ;
				s << "sc_trace(trcf, ClkS" << *U << ", \"" << mSpec->GetName(*U) << "_clk\");" << endl ;
			}
			if (If.GetDirection() == Interface::IN && IsBound) {
				s << "sc_trace(trcf, D" << *U << "_Data, \"" << mSpec->GetName(*U) << "_data_in\");" << endl;
				s << "sc_trace(trcf, D" << *U << "_Valid, \"" << mSpec->GetName(*U) << "_valid_in\");" << endl;
				s << "sc_trace(trcf, D" << *U << "_Ack, \"" << mSpec->GetName(*U) << "_ack_out\");" << endl;
				s << "sc_trace(trcf, D" << *U << "_Full, \"" << mSpec->GetName(*U) << "_full_out\");" << endl ;
			}
		}
	}
	return s.str() ;

}

void SyscCodeGen::SyscClose() {

	(*mF) << "}" << endl;
}

string SyscCodeGen::SyscSource(int S, string Port) {

	stringstream s;

	s << "\t" << " //Source " << mSpec->GetName(S) << " port  " << Port
	<< " has id " << S << endl;

	///////////////////////////////////////////////////////////////////////////
	//////                Flows information
	///////////////////////////////////////////////////////////////////////////
	s << "\t" << "vector< Flow > Flows" << S << ";" << endl;

	IdGraph::v_iterator D;

	//TODO: look at the commodities on the edge bound to the port insted of checking the specification
	for (D = mSpec->v_begin(); D != mSpec->v_end(); D++) {
		if (mSpec->InE(S, *D) ) {
			//TODO: make the packet size a parameter
			s << "\t" << "F.PacketSize = 4 ; " << endl;
			s << "\t" << "F.Destination = " << *D << ";" << endl;
			s << "\t" << "F.Bandwidth = " << (*mSpec)[Edge(S,*D)].PRJ(CommoditySet)GetAggregateBandwidthValue() << ";" << endl;
			s << "\t" << "Flows" << S << ".push_back( F ) ;" << endl;
		}
	}

	///////////////////////////////////////////////////////////////////////////
	//////                Instantiate the source and the clock
	///////////////////////////////////////////////////////////////////////////

	s << "\t" << "SourceIp<FLITWIDTH> S" << S << "( \"s_" << mSpec->GetName(S) << "\" , "<< S
	<< " , Flows" << S <<" ) ;" << endl;
	s << "\t" << "sc_clock ClkS" << S << "( \"ClkS" << S
	<< "\" , CLOCKPERIOD , SC_SEC ) ;" << endl;
	s << "\t" << "S" << S << ".Clock( ClkS" << S <<" ) ;" << endl;

	return s.str();
}

string SyscCodeGen::SyscDest(int D, string Port) {
	stringstream s;
	s << "\t"<< "//Destination " << mSpec->GetName(D) << " port " << Port
	<< " has id " << D << endl;
	s << "\t" << "DestIp<FLITWIDTH> D" << D << "( \"d_" << mSpec->GetName(D) << "\" , " << D
	<< " ) ;" << endl;
	s << "\t" << "sc_clock ClkD" << D << "( \"ClkD" << D
	<< "\" , CLOCKPERIOD , SC_SEC ) ;" << endl;
	s << "\t" << "D" <<D << ".Clock( ClkD" << D << " ) ;" << endl;
	s << "\t" << "_CosiAddDestIp_( &D" << D << " ) ;" << endl;
	return s.str();

}

string SyscCodeGen::SyscRouter(int V) {
	stringstream s;
	TransferTable::iterator Entry;
	TransferTable T = (*mI)[V].PRJ(TransferTable)Get();

	//---------------------------------------------------------------------------
	//                     Generate the routing table
	//---------------------------------------------------------------------------

	s << "\t" << "map< pair<int,int> , int > RT" << V << " ;" << endl;

	for (Entry = T.TransferTableBegin(); Entry != T.TransferTableEnd(); Entry++) {
		int Sid = mSpec->GetId((Entry->first).first);
		int Did = mSpec->GetId((Entry->first).second);
		int Pid = OutputIndex(V, Entry->second);
		s << "\t" << "RT" << V << "[ pair<int,int>( " << Sid << " , " << Did
		<< ") ] = " << Pid << " ; " << endl;
	}

	//---------------------------------------------------------------------------
	//                     Generate weight vector
	//
	// Has to take into account the number of inputs that
	// share the same output. In particular given two inputs i1 and i2, let I1
	// and I2 be the set of inputs that share the same output of i1 and i2,
	// respectively.
	// Then, w(i1) / w(i2) = bw(i1)|I1| / ( bw(i2)|I2|).
	// Currently this is not implemented, therefore the systemc simulation
	// shows an unfairness phenomenon.
	//---------------------------------------------------------------------------
	s << "\t" << "vector<double> Weights" << V << "( " << mI->InDegree(V)
	<< " ) ;" << endl;
	//Compute the total input flow
	IdGraph::list_iterator U;
	double InputRate = 0.0;
	for (U = mI->in_begin(V); U != mI->in_end(V); U++) {
		InputRate += (*mI)[Edge(*U,V)].PRJ(CommoditySet)GetAggregateBandwidthValue();
	}

	for (U = mI->in_begin(V); U != mI->in_end(V); U++) {
		string P = (*mI)[V].PRJ(Ports)IsBoundTo(Edge(*U, V), Interface::IN);
		s << "\t" << "Weights" << V << "[ " << InputIndex(V, P) << "] = " << (*mI)[Edge(*U,V)].GetAggregateBandwidthValue() / InputRate << " ; "
		<< endl;

	}

	//---------------------------------------------------------------------------
	//                     Instantiate the router and the clock
	//---------------------------------------------------------------------------

	s << "\t" << "Router< " << mI->InDegree(V) << " , " << mI->OutDegree(V)
	<< ", FLITWIDTH > R" << V << "( \"R" << V << "\" , 1 , 2 , RT" << V
	<< " , Weights" << V <<" , TechParam ) ; " << endl;
	s << "\t" << "sc_clock ClkR" << V << "( \"ClkR" << V
	<< "\" , CLOCKPERIOD , SC_SEC ) ;" << endl;
	s<< "\t" << "R" << V << ".Clock( ClkR" << V << ") ;" << endl;
	return s.str();

}

string SyscCodeGen::SyscSourceNetworkInterface(int S, string P) {

	stringstream s;
	TransferTable T;
	TransferTable::iterator Entry;
	T = (*mI)[S].PRJ(TransferTable)Get();
	//---------------------------------------------------------------------------
	//                     Generate the routing table
	//---------------------------------------------------------------------------

	s << "\t" << "map< pair<int,int> , int > ST" << S << " ;" << endl;
	for (Entry = T.TransferTableBegin(); Entry != T.TransferTableEnd(); Entry++) {
		int Sid = mSpec->GetId((Entry->first).first);
		int Did = mSpec->GetId((Entry->first).second);
		int Pid = OutputIndex(S, Entry->second);
		s << "\t" << "ST" << S << "[ pair<int,int>( " << Sid << " , " << Did
		<< ") ] = " << Pid << " ; " << endl;
	}

	//---------------------------------------------------------------------------
	//                     Generate weight vector
	//---------------------------------------------------------------------------
	s << "\t" << "vector<double> Sweights" << S << "( " << 1 << " ) ;" << endl;
	s << "\t" << "Sweights" << S << "[ 0 ] = 1.0 ; " << endl;

	//---------------------------------------------------------------------------
	//                     Instantiate the router and the clock
	//---------------------------------------------------------------------------

	s << "\t" << "Router< 1 , " << mI->OutDegree(S) << ", FLITWIDTH > Sif" << S
	<< "( \"Sif" << S << "\" , 1 , 2 , ST" << S << " , Sweights" << S
	<<" , TechParam ) ; " << endl;
	s << "\t" << "sc_clock ClkSif" << S << "( \"ClkSif" << S
	<< "\" , CLOCKPERIOD , SC_SEC ) ;" << endl;
	s<< "\t" << "Sif" << S << ".Clock( ClkSif" << S << ") ;" << endl;
	return s.str();
}

string SyscCodeGen::SyscDestNetworkInterface(int D, string P) {
	stringstream s;
	map< pair<int,int> , int > RoutingTable;
	map< pair<int,int> , int >::iterator Entry;

	//---------------------------------------------------------------------------
	//                     Generate the routing table
	//
	// We need to create the routing table because destinations don't
	// have one. We look at the PtP graph and for each requirements
	// (s,d) to this destination we add an entry (<s,d>,0) to the
	// routing table.
	//---------------------------------------------------------------------------
	IdGraph::list_iterator S;
	for (S = mSpec->in_begin(D); S != mSpec->in_end(D); S++) {
		if (mSpec->InE(*S, D) ) {
			RoutingTable[ pair<int,int>(*S,D) ] = 0;
		}
	}

	s << "\t" << "map< pair<int,int> , int > DT" << D << " ;" << endl;
	for (Entry = RoutingTable.begin(); Entry != RoutingTable.end(); Entry++) {
		s << "\t" << "DT" << D << "[ pair<int,int>( " << (Entry->first).first << " , " << (Entry->first).second << ") ] = " << Entry->second << " ; "
		<< endl;
	}

	//---------------------------------------------------------------------------
	//                     Generate weight vector
	//---------------------------------------------------------------------------
	s << "\t" << "vector<double> Dweights" << D << "( " << mI->InDegree(D)
	<< " ) ;" << endl;
	//Compute the total input flow by summing all aggregate flows
	double InputRate = 0.0;
	for (S = mSpec->in_begin(D); S != mSpec->in_end(D); S++) {
		if (mI->InE(*S, D) ) {
			InputRate += (*mI)[Edge(*S,D)].PRJ(CommoditySet)GetAggregateBandwidthValue();
		}
	}

	for (S = mSpec->in_begin(D); S != mSpec->in_end(D); S++) {
		if (mI->InE(*S, D) ) {
			string P = (*mI)[D].PRJ(Ports)IsBoundTo(Edge(*S, D), Interface::IN);
			s << "\t" << "Dweights" << D << "[ " << InputIndex(D, P) << "] = "
			<< (*mI)[Edge(*S,D)].PRJ(CommoditySet)GetAggregateBandwidthValue()
			/ InputRate << " ; " << endl;
		}
	}

	//---------------------------------------------------------------------------
	//                     Instantiate the router and the clock
	//---------------------------------------------------------------------------

	s << "\t" << "Router< " << mI->InDegree(D) << " , 1 , FLITWIDTH > Dif" << D
	<< "( \"Dif" << D << "\" , 1 , 2 , DT" << D << " , Dweights" << D
	<<" , TechParam ) ; " << endl;
	s << "\t" << "sc_clock ClkDif" << D << "( \"ClkDif" << D
	<< "\" , CLOCKPERIOD , SC_SEC ) ;" << endl;
	s<< "\t" << "Dif" << D << ".Clock( ClkDif" << D << ") ;" << endl;
	return s.str();
}

string SyscCodeGen::SyscConnect(
		cosi::commstruct::onchipcommunication::Implementation* G, int U, int V) {
	stringstream s;
	return s.str();
}

void SyscCodeGen::SyscPrintStat(ofstream* f,
		cosi::commstruct::onchipcommunication::Implementation* G,
		cosi::commstruct::onchipcommunication::Specification* PtP) {
	//Gather energy from all routers
	(*mF) << "double TotalRouterEnergy = 0 ; " << endl;

	for (int RouterId = G->Ns() + G->Nd(); RouterId < G->Ns() + G->Nd()
			+ G->Nr(); RouterId++) {
		(*mF) << "TotalRouterEnergy += R" << RouterId << "->GetEnergy( );"
		<< endl;
	}
	//Gather Energy for all wires
	(*mF) << "double TotalWireEnergy = 0 ; " << endl;
	for (int SourceId = 0; SourceId < G->Order(); SourceId++) {
		for (int DestId = 0; DestId < G->Order(); DestId++) {
			if (G->InE(SourceId, DestId) ) {
				(*mF) << "TotalWireEnergy += N" << SourceId << "_N"<< DestId
				<< "->total_energy ; "<< endl;

			}
		}
	}

	(*mF) << "cout << \"Power report :\"<<endl ; " << endl;
	(*mF) << "cout << \"\t Wires : \" << TotalWireEnergy << endl ;" << endl;
	(*mF) << "cout << \"\t Routers : \" << TotalRouterEnergy << endl ;" <<endl;
}

int SyscCodeGen::InputIndex(int V, string P) {
	//TODO : what is there is no such combination in the map?
	return mInputPortIndex[pair<int,string>(V ,P )];
}

int SyscCodeGen::OutputIndex(int V, string P) {
	//TODO : what is there is no such combination in the map?
	return mOutputPortIndex[pair<int,string>(V ,P )];
}

void SyscCodeGen::InputIndex(int V, string P, int Pid) {
	mInputPortIndex[pair<int,string>(V ,P )] = Pid;
}

void SyscCodeGen::OutputIndex(int V, string P, int Pid) {
	mOutputPortIndex[pair<int,string>(V ,P )] = Pid;
}

}
}
}
